"""
Authentication service following SOLID principles.
"""

from datetime import timedelta
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from fastapi import HTTPException, status
from .models import User, UserCreate, UserResponse, Token
from .password_handler import password_handler
from .jwt_handler import jwt_handler
from ..config.settings import get_settings


class AuthService:
    """Authentication service for user management."""
    
    def __init__(self):
        self.settings = get_settings()
    
    async def create_user(self, db: AsyncSession, user_data: UserCreate) -> UserResponse:
        """Create a new user."""
        # Check if user already exists
        existing_user = await self.get_user_by_email(db, user_data.email)
        if existing_user:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Email already registered"
            )
        
        existing_username = await self.get_user_by_username(db, user_data.username)
        if existing_username:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Username already taken"
            )
        
        # Create new user
        hashed_password = password_handler.hash_password(user_data.password)
        db_user = User(
            email=user_data.email,
            username=user_data.username,
            hashed_password=hashed_password
        )
        
        db.add(db_user)
        await db.commit()
        await db.refresh(db_user)
        
        return UserResponse.model_validate(db_user)
    
    async def authenticate_user(
        self,
        db: AsyncSession,
        email: str,
        password: str
    ) -> Optional[User]:
        """Authenticate user with email and password."""
        user = await self.get_user_by_email(db, email)
        if not user:
            return None
        
        if not password_handler.verify_password(password, user.hashed_password):
            return None
        
        return user
    
    async def get_user_by_email(self, db: AsyncSession, email: str) -> Optional[User]:
        """Get user by email."""
        result = await db.execute(select(User).where(User.email == email))
        return result.scalar_one_or_none()
    
    async def get_user_by_username(self, db: AsyncSession, username: str) -> Optional[User]:
        """Get user by username."""
        result = await db.execute(select(User).where(User.username == username))
        return result.scalar_one_or_none()
    
    async def get_user_by_id(self, db: AsyncSession, user_id: int) -> Optional[User]:
        """Get user by ID."""
        result = await db.execute(select(User).where(User.id == user_id))
        return result.scalar_one_or_none()
    
    def create_access_token(self, user_id: int) -> Token:
        """Create access token for user."""
        access_token_expires = timedelta(
            minutes=self.settings.access_token_expire_minutes
        )
        access_token = jwt_handler.create_access_token(
            data={"sub": str(user_id)},
            expires_delta=access_token_expires
        )
        return Token(access_token=access_token)
    
    async def get_current_user(self, db: AsyncSession, token: str) -> User:
        """Get current user from token."""
        credentials_exception = HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not validate credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )
        
        user_id = jwt_handler.get_user_id_from_token(token)
        if user_id is None:
            raise credentials_exception
        
        user = await self.get_user_by_id(db, int(user_id))
        if user is None:
            raise credentials_exception
        
        return user


# Global auth service instance
auth_service = AuthService()